using System;
using System.Collections.Generic;
using System.Text;

namespace RapidHDL
{
    public class TestPipelineAssemblerBuffer : RapidHardware
    {
        PipelineSerialAssembler oAssembler;
        PipelineBuffer oBuffer;

        public override bool ConfigureSettings()
        {
            Settings.UseStart = false;
            Settings.BuildHardware = true;
            Settings.ForceBuildHardware = false;
            Settings.RunFromXilinx = true;
            Settings.ClockFrequency = 10;
            Settings.UseSDRAM = true;
            Settings.BuildRemote = false;
            return true;
        }

        public override bool GenerateStructure(TopLevelComponent TopLevelComponent)
        {
            TopLevelComponent.TestBusWrite.Join(0);

            oAssembler = new PipelineSerialAssembler(TopLevelComponent, "assembler", TopLevelComponent.MainClock, TopLevelComponent.MainReset, 4, 2, 2, 4);
            oBuffer = new PipelineBuffer(TopLevelComponent, "buffer", TopLevelComponent.MainClock, TopLevelComponent.MainReset, 4, 4);

            oBuffer.OutputBus.Join(oAssembler.InputBus);

            SystemInterface.AddSignalSource("data_i", oBuffer.InputBus.Data, 0);
            SystemInterface.AddSignalSource("data_ready_i", oBuffer.InputBus.DataReady, 0);
            SystemInterface.AddSignalSource("stall_i", oAssembler.OutputBus.Stall, 0);

            return true;
        }

        public override bool ConfigureSignalViews(TopLevelComponent TopLevelComponent)
        {
            //SystemInterface.FormatSignalView("pipe0_o", SignalFormat.Unsigned);

            SystemInterface.AddSignalView("data_in", oAssembler.InputBus.Data);

            SystemInterface.AddSignalView("data_o", oAssembler.OutputBus.Data);
            SystemInterface.AddSignalView("data_ready_o", oAssembler.OutputBus.DataReady);
            SystemInterface.AddSignalView("stall_o", oAssembler.InputBus.Stall);
            SystemInterface.AddSignalView("buffer_stall", oBuffer.OutputBus.Stall);
            SystemInterface.AddSignalView("buffer_data", oBuffer.OutputBus.Data);

            SystemInterface.AddSignalView("state_reset", oAssembler.oStateMachine.GetState("state_reset").StateCurrentNodes);
            SystemInterface.AddSignalView("state_0", oAssembler.oStateMachine.GetState("state_0").StateCurrentNodes);
            SystemInterface.AddSignalView("state_1", oAssembler.oStateMachine.GetState("state_1").StateCurrentNodes);
            SystemInterface.AddSignalView("state_2", oAssembler.oStateMachine.GetState("state_2").StateCurrentNodes);
            SystemInterface.AddSignalView("state_final", oAssembler.oStateMachine.GetState("state_final").StateCurrentNodes);
            SystemInterface.AddSignalView("state_stall", oAssembler.oStateMachine.GetState("state_stall").StateCurrentNodes);
            SystemInterface.AddSignalView("state_stall_final", oAssembler.oStateMachine.GetState("state_stall_final").StateCurrentNodes);

            for (int i = 0; i < 4; i++)
            {
                //AddStageView(oBuffer.Stages[i], i);
            }
            return true;
        }

        private void AddStageView(PipelineBufferStage poStage, int piIdx)
        {
            SystemInterface.AddSignalView("stage_out_" + piIdx.ToString(),poStage.OutputBus.Data);
            SystemInterface.AddSignalView("stage_dr_" + piIdx.ToString(), poStage.OutputBus.DataReady );
            SystemInterface.AddSignalView("stage_stall_" + piIdx.ToString(), poStage.OutputBus.Stall);
        }

        private void ViewStages(HardwareScript poScript, int piTime)
        {
            poScript.Echo(piTime, "========================================================  Time is " + piTime.ToString());
            for (int i = 0; i < 4; i++)
            {
                poScript.Echo(piTime,"------------------------ " + piTime.ToString() + " -- Stage " + i.ToString()) ;
                poScript.SignalView(piTime, "stage_dr_" + i.ToString());
                poScript.SignalView(piTime, "stage_out_" + i.ToString());
                poScript.SignalView(piTime, "stage_stall_" + i.ToString());
            }
            poScript.Echo(piTime, "------------------------");
            poScript.SignalView(piTime, "data_in");
            poScript.Echo(piTime, "========================================================");
        }


        private void ViewOutputs(HardwareScript poScript, int piTime)
        {
            poScript.Echo(piTime, "========================================================  Time is " + piTime.ToString());
            poScript.Echo(piTime, "*****");
            poScript.SignalView(piTime, "data_in");
            poScript.SignalView(piTime, "data_o");
            poScript.SignalView(piTime, "data_ready_o");
            poScript.SignalView(piTime, "stall_o");
            poScript.SignalView(piTime, "buffer_stall");
            poScript.SignalView(piTime, "buffer_data");
            poScript.Echo(piTime, "-----");
            poScript.SignalView(piTime, "state_reset");
            poScript.SignalView(piTime, "state_0");
            poScript.SignalView(piTime, "state_1");
            poScript.SignalView(piTime, "state_2");
            poScript.SignalView(piTime, "state_stall");
            poScript.SignalView(piTime, "state_stall_final");
            poScript.SignalView(piTime, "state_final");
            poScript.Echo(piTime, "=====");
        }

        private void SetInputs(HardwareScript poScript, int piTime, int piData, int piDataReady, int piStall)
        {
            poScript.SignalOut(piTime, "data_i", piData.ToString(), SignalFormat.Unsigned);
            poScript.SignalOut(piTime, "data_ready_i", piDataReady.ToString());
            poScript.SignalOut(piTime, "stall_i", piStall.ToString());
            //poScript.SignalOut(piTime, "data_i", piData.ToString());
            //poScript.Pause(piTime + 1);
            //ViewOutputs(poScript, piTime);
        }

        public void TestSequence(HardwareScript poScript, int piTime, int piA, int piB, int piC, int piD, int piE)
        {
            int iTime = piTime;

            SetInputs(poScript, iTime++, piA, 1, 0);
            SetInputs(poScript, iTime++, piB, 1, 0);
            SetInputs(poScript, iTime++, piC, 1, 0);
            SetInputs(poScript, iTime++, piD, 1, 0);
            SetInputs(poScript, iTime++, piE, 1, 0);
        }

        public override bool GenerateHardwareScripts()
        {
            HardwareScript oScript = HardwareScripts.NewScript("test");
            oScript.NoReset = false;
            
            /*TestSequence(oScript, 2, 1, 7, 8, 15, 2);
            ViewOutputs(oScript, 7);
            ViewOutputs(oScript, 8);
            ViewOutputs(oScript, 9);
            oScript.Pause(9);

            int iTime = 11;
            oScript.Echo(iTime, "Stall Test");
            SetInputs(oScript, iTime++, 1, 1, 1);
            SetInputs(oScript, iTime++, 7, 1, 1);
            SetInputs(oScript, iTime++, 8, 1, 1);
            SetInputs(oScript, iTime++, 15, 1, 1);
            //SetInputs(oScript, iTime++, 15, 1, 1);
            SetInputs(oScript, iTime++, 14, 1, 1);
            SetInputs(oScript, iTime++, 14, 1, 0);
            SetInputs(oScript, iTime++, 14, 1, 0);
            oScript.Pause(iTime);
            oScript.Echo(iTime, "End Stall Test");
            oScript.Echo(iTime, "order test");
            SetInputs(oScript, iTime++, 1, 1, 0);
            SetInputs(oScript, iTime++, 7, 1, 0);
            SetInputs(oScript, iTime++, 1, 1, 0);
            SetInputs(oScript, iTime++, 7, 1, 0);
            SetInputs(oScript, iTime++, 15, 1, 0);
            SetInputs(oScript, iTime++, 1, 1, 0);
            SetInputs(oScript, iTime++, 7, 1, 0);
            SetInputs(oScript, iTime++, 8, 1, 0);
            SetInputs(oScript, iTime++, 15, 1, 0);
            oScript.Echo(iTime, "end order test");
            SetInputs(oScript, iTime++, 1, 1, 0);
            SetInputs(oScript, iTime++, 7, 1, 0);
            SetInputs(oScript, iTime++, 8, 1, 0);
            SetInputs(oScript, iTime++, 7, 0, 0);
            SetInputs(oScript, iTime++, 7, 0, 0);
            SetInputs(oScript, iTime++, 15, 1, 0);
            SetInputs(oScript, iTime++, 8, 1, 0);
            SetInputs(oScript, iTime++, 8, 1, 0);
            iTime = 40;
            */
            oScript.Echo(40, "Second Stall Test");
            SetInputs(oScript, 41, 8, 1, 0);
            SetInputs(oScript, 42, 1, 1, 0);
            SetInputs(oScript, 43, 7, 1, 0);
            SetInputs(oScript, 44, 8, 1, 0);
            SetInputs(oScript, 45, 14, 1, 1);
            SetInputs(oScript, 46, 1, 1, 1);
            SetInputs(oScript, 47, 7, 1, 1);
            SetInputs(oScript, 48, 8, 1, 0);
            SetInputs(oScript, 49, 15, 1, 1);
            SetInputs(oScript, 50, 1, 1, 0);
            SetInputs(oScript, 51, 7, 1, 0);
            SetInputs(oScript, 52, 8, 1, 0);
            SetInputs(oScript, 53, 14, 1, 0);
            SetInputs(oScript, 54, 0, 0, 0);
            SetInputs(oScript, 55, 0, 0, 0);
            SetInputs(oScript, 56, 0, 0, 0);
            SetInputs(oScript, 57, 0, 0, 0);

            /*ViewStages(oScript, 44);
            ViewStages(oScript, 45);
            ViewStages(oScript, 46);
            ViewStages(oScript, 47);
            ViewStages(oScript, 48);*/
            for (int iTime = 48; iTime < 60; iTime++)
            {
                ViewOutputs(oScript, iTime);
            }


            //SetInputs(oScript, 0, 0, 0, 0, 0, 0);
            //ShowOutputs(oScript, 0);

            return true;
        }

    }
}

